package base;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import org.testng.Assert;

import java.util.List;

/**
 * JSON断言工具类，支持JSONPath表达式
 */
public class JsonAssertion {

    private final String jsonString;

    public JsonAssertion(String jsonString) {
        this.jsonString = jsonString;
    }

    /**
     * 验证JSON中指定路径的值等于期望值
     *
     * @param jsonPath JSONPath表达式
     * @param expected 期望值
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertEquals(String jsonPath, Object expected) {
        try {
            Object actual = JsonPath.read(jsonString, jsonPath);

            // 识别JSONArray
            if (expected instanceof String && ((String) expected).startsWith("[") && ((String) expected).endsWith("]")) {
                // 如果期望值是字符串形式的数组，转换为对象进行比较
                ObjectMapper mapper = new ObjectMapper();
                Object expectedObj = mapper.readTree((String) expected);
                Object actualObj = mapper.readTree(actual.toString());
                Assert.assertEquals(actualObj, expectedObj, "JSONPath: " + jsonPath);
            } else {
                Assert.assertEquals(actual, expected, "JSONPath: " + jsonPath);
            }
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON中指定路径的值不等于期望值
     *
     * @param jsonPath JSONPath表达式
     * @param expected 期望值
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertNotEquals(String jsonPath, Object expected) {
        try {
            Object actual = JsonPath.read(jsonString, jsonPath);
            Assert.assertNotEquals(actual, expected, "JSONPath: " + jsonPath);
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON中指定路径存在
     *
     * @param jsonPath JSONPath表达式
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertPathExists(String jsonPath) {
        try {
            JsonPath.read(jsonString, jsonPath);
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON中指定路径不存在
     *
     * @param jsonPath JSONPath表达式
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertPathNotExists(String jsonPath) {
        try {
            JsonPath.read(jsonString, jsonPath);
            Assert.fail("JSONPath should not exist: " + jsonPath);
        } catch (PathNotFoundException e) {
            // 期望的结果，路径不存在
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON中指定路径的值为null
     *
     * @param jsonPath JSONPath表达式
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertNull(String jsonPath) {
        try {
            Object actual = JsonPath.read(jsonString, jsonPath);
            Assert.assertNull(actual, "JSONPath: " + jsonPath);
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON中指定路径的值不为null
     *
     * @param jsonPath JSONPath表达式
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertNotNull(String jsonPath) {
        try {
            Object actual = JsonPath.read(jsonString, jsonPath);
            Assert.assertNotNull(actual, "JSONPath: " + jsonPath);
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON数组的大小
     *
     * @param jsonPath JSONPath表达式，应指向一个数组
     * @param expectedSize 期望的数组大小
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertArraySize(String jsonPath, int expectedSize) {
        try {
            List<?> array = JsonPath.read(jsonString, jsonPath);
            Assert.assertEquals(array.size(), expectedSize, "Array size at JSONPath: " + jsonPath);
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 验证JSON中指定路径的值包含特定字符串
     *
     * @param jsonPath JSONPath表达式
     * @param expectedSubstring 期望包含的子字符串
     * @return JsonAssertion 返回自身以支持链式调用
     */
    public JsonAssertion assertContains(String jsonPath, String expectedSubstring) {
        try {
            String actual = JsonPath.read(jsonString, jsonPath);
            Assert.assertTrue(actual.contains(expectedSubstring), 
                "Expected '" + actual + "' to contain '" + expectedSubstring + "' at JSONPath: " + jsonPath);
        } catch (PathNotFoundException e) {
            Assert.fail("JSONPath not found: " + jsonPath);
        } catch (Exception e) {
            Assert.fail("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage());
        }
        return this;
    }

    /**
     * 获取JSON中指定路径的值
     *
     * @param jsonPath JSONPath表达式
     * @param <T> 返回值类型
     * @return 指定路径的值
     */
    public <T> T getValue(String jsonPath) {
        try {
            return JsonPath.read(jsonString, jsonPath);
        } catch (PathNotFoundException e) {
            throw new RuntimeException("JSONPath not found: " + jsonPath, e);
        } catch (Exception e) {
            throw new RuntimeException("Error reading JSONPath: " + jsonPath + ", error: " + e.getMessage(), e);
        }
    }
}
